﻿//svn test

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections.ObjectModel;
using Compiler;
using System.IO;
using System.Diagnostics;
using Compiler.PrebuildParser;


namespace GrammarTest
{
    public abstract class BoolNode : INode
    {

    }

    public class QuestNode : BoolNode
    {
        BoolNode left, right;

        public QuestNode(BoolNode left, BoolNode right)
        {
            this.left = left;
            this.right = right;
        }

        public override string ToString()
        {
            return string.Format("Q({0}, {1})", left.ToString(), right.ToString());
        }
    }

    public class ProbeNode : BoolNode
    {
        BoolNode left, right;

        public ProbeNode(BoolNode left, BoolNode right)
        {
            this.left = left;
            this.right = right;
        }

        public override string ToString()
        {
            return string.Format("P({0}, {1})", left.ToString(), right.ToString());
        }
    }

    public class NumberNode : BoolNode
    {
        int num;
        public NumberNode(int n)
        {
            num = n;
        }

        public override string ToString()
        {
            return num.ToString();
        }
    }

    public class AndNode : BoolNode
    {
        BoolNode left, right;

        public AndNode(BoolNode left, BoolNode right)
        {
            this.left = left;
            this.right = right;
        }

        public override string ToString()
        {
            return string.Format("({0} AND {1})", left.ToString(), right.ToString());
        }
    }

    public class OrNode : BoolNode
    {
        BoolNode left, right;

        public OrNode(BoolNode left, BoolNode right)
        {
            this.left = left;
            this.right = right;
        }

        public override string ToString()
        {
            return string.Format("({0} OR {1})", left.ToString(), right.ToString());
        }

    }

    public class NotNode : BoolNode
    {
        BoolNode child;

        public NotNode(BoolNode child)
        {
            this.child = child;
        }

        public override string ToString()
        {
            return string.Format("NOT({0})", child.ToString());
        }
    }

    class Factory : INodeFactory
    {
        public INode OnTerminal(LexerPair lexerPair)
        {
            var term = lexerPair.Token.Terminal;

            if (term.ID == 5)
                return new NumberNode(int.Parse(lexerPair.Lexeme));

            return null;
        }

        public INode OnNonterminal(Production production, Stack<INode> nodeStack)
        {
            if(production.ID == 1)
            {
                var childs = nodeStack.PopN(2).Cast<BoolNode>().ToList();
                return new OrNode(childs[0], childs[1]);
            }
            if (production.ID == 3)
            {
                var childs = nodeStack.PopN(2).Cast<BoolNode>().ToList();
                return new AndNode(childs[0], childs[1]);
            }
            if (production.ID == 6)
            {
                var childs = nodeStack.PopN(1).Cast<BoolNode>().ToList();
                return new NotNode(childs[0]);
            }
            if (production.ID == 8)
            {
                var childs = nodeStack.PopN(2).Cast<BoolNode>().ToList();
                return new QuestNode(childs[0], childs[1]);
            }
            if (production.ID == 9)
            {
                var childs = nodeStack.PopN(2).Cast<BoolNode>().ToList();
                return new ProbeNode(childs[0], childs[1]);
            }

            return null;
        }
    }

    class Program
    {
        static void Main(string[] args)
        {


            Terminal _or = new Terminal(1, "|");
            Terminal _and = new Terminal(2, "&");
            Terminal _lb = new Terminal(3, "lb");
            Terminal _rb = new Terminal(4, "rb");
            Terminal _num = new Terminal(5, "num");
            Terminal _not = new Terminal(6, "not");
            Terminal _quest = new Terminal(7, "q");
            Terminal _probe = new Terminal(8, "p");
            Terminal _comma = new Terminal(9, ",");

            Token or = new Token(@"\|", "OR", 1, _or);
            Token and = new Token(@"&", "AND", 1, _and);
            Token lb = new Token(@"\(", "LEFTBRACKET", 1, _lb);
            Token rb = new Token(@"\)", "RIGHTBRACKET", 1, _rb);
            Token num = new Token(@"[1-9][0-9]*", "NUMBER", Int32.MaxValue, _num);
            Token not = new Token("!", "NOT", 1, _not);
            Token quest = new Token("Q", "QUEST", 1, _quest);
            Token probe = new Token("P", "PROBE", 1, _probe);
            Token comma = new Token(",", ",", 1, _comma);

            Nonterminal Z = new Nonterminal(0, "Start");
            Nonterminal E = new Nonterminal(1, "E");
            Nonterminal T = new Nonterminal(2, "T");
            Nonterminal F = new Nonterminal(3, "F");
            Nonterminal U = new Nonterminal(4, "U");


            Production P1 = new Production(0, Z, E);
            Production P2 = new Production(1, E, E, _or, T);
            Production P3 = new Production(2, E, T);
            Production P4 = new Production(3, T, T, _and, F);
            Production P5 = new Production(4, T, F);

            Production P6 = new Production(5, F, U);
            Production P7 = new Production(6, F, _not, U);

            Production P8 = new Production(7, U, _lb, E, _rb);
            Production P9 = new Production(8, U, _quest, _lb, _num, _comma, _num, _rb); // Q(num,num)
            Production P10 = new Production(9, U, _probe, _lb, _num, _comma, _num, _rb); // Q(num,num)

            Lexer lexer = new Lexer(new List<Token> { or, and, lb, rb, num, not, quest, probe, comma });
            Grammar grammar = new Grammar(Z, P1, P2, P3, P4, P5, P6,P7,P8, P9, P10);
            ParseTable parseTable = Builder.Build(grammar, Builder.BuildMethod.SLR, null);

            Parser parser = new Parser(parseTable, lexer, new Factory());

            while (true)
            {
                try
                {

                    Console.Write(">> ");
                    string source = Console.ReadLine();


                    parser.SetSource(source);
                    parser.DoParse();
                }
                catch (UnknownLexeme e)
                {
                    //Console.WriteLine();
                    Console.WriteLine("Unknown: {0}", e.lexerPair.Lexeme);
                }
                catch (AcceptException accept)
                {
                    //Console.WriteLine();
                    Console.WriteLine("ACCEPT");
                    Console.WriteLine(accept.RootNode.ToString());
                }
                catch (NotAcceptException na)
                {
                    //Console.WriteLine();
                    Console.WriteLine("Not accepted. Rest of Source\n{0}", na.RestOfSource);


                }
              //  Console.ReadLine();
            }

            Console.ReadKey(true);
            return;

            //Parser parser = EBNF_Parser.Build();

            //while (true)
            //{
            //    try
            //    {
            //        Console.WriteLine();
            //        string source =
            //            File.ReadAllText(@"C:\Users\benjamin.CKHOME\Documents\Visual Studio 2008\Projects\_Fun\Compiler\Compiler\EbnfExample.txt");
            //         //    Console.ReadLine();
            //        parser.SetSource(source);
            //        parser.DoParse();
            //    }
            //    catch (UnknownLexeme e)
            //    {
            //        Console.WriteLine();
            //        Console.WriteLine("Unknown: {0}", e.lexerPair.Lexeme);
            //    }
            //    catch (AcceptException accept)
            //    {
            //        Console.WriteLine();
            //        Console.WriteLine("ACCEPT");
            //        if (accept.RootNode != null)
            //        {
            //            Console.WriteLine();
            //            Console.WriteLine("INPUT:\n" + accept.RootNode.ToString());

            //            //EbnfGrammarBuild build = new EbnfGrammarBuild();
            //            ProgramNode root = (ProgramNode)accept.RootNode;

            //            Console.WriteLine();

            //            var stack = new Stack<EbnfAssign>();
            //            root.Expand(stack);
                        
            //            Console.WriteLine("EXPAND:\n" + root.ToString());
            //            //Console.WriteLine("value: {0}", ((EBNF_Node)accept.RootNode).ToString());
                        
            //            Ebnf2GrammarConvertData data = new Ebnf2GrammarConvertData();
            //            root.Convert2Grammar(data);
            //            Grammar grammar = data.ConstructGrammar();
            //            Console.WriteLine("\nGRAMMAR:");
            //            Console.WriteLine(grammar.ToString());

                      ////  Console.WriteLine("EXPAND:\n" + root.ToString());
                      ////  //Console.WriteLine("value: {0}", ((EBNF_Node)accept.RootNode).ToString());

                      ////  Ebnf2GrammarConvertData data = new Ebnf2GrammarConvertData();
                      ////  root.Convert2Grammar(data);
                      ////  Grammar grammar = data.ConstructGrammar();
                      ////  Console.WriteLine("\nGRAMMAR:");
                      ////  Console.WriteLine(grammar.ToString());

                        //Stopwatch sw = new Stopwatch();
                        //sw.Start();
                        //var parseTable = Builder.Build(grammar, Builder.BuildMethod.LR1, null);// @"C:\Users\benjamin.CKHOME\Desktop\graph\not_lr1.gv");
                        //sw.Stop();
                        //Console.WriteLine(sw.ElapsedMilliseconds.ToString());
                        //Console.WriteLine(parseTable.Print());


                      

            //        }
            //    }
            //    catch (NotAcceptException na)
            //    {
            //        Console.WriteLine();
            //        Console.WriteLine("Not accepted. Rest of Source\n{0}", na.RestOfSource);
                    
            //    }
            //    Console.ReadLine();
            //}

            //Console.ReadLine();
        }

        private static void NewMethod()
        {
            var Start = new Nonterminal(0, "Z");

            var E = new Nonterminal(0, "E");
            var E_ = new Nonterminal(1, "E'");
            var T = new Nonterminal(2, "T");
            var T_ = new Nonterminal(3, "T'");
            var F = new Nonterminal(4, "F");

            var a = new Terminal(5, "a");
            var lb = new Terminal(6, "(");
            var rb = new Terminal(7, ")");
            var plus = new Terminal(8, "+");
            var mul = new Terminal(9, "*");

            var PST = new Production(0, Start, E);

            var P0 = new Production(10, E, T, E_);
            var P1 = new Production(11, E_, plus, T, E_);
            var P2 = new Production(12, E_, Symbol.Epsilon);
            var P3 = new Production(13, T, F, T_);
            var P4 = new Production(14, T_, mul, F, T_);
            var P5 = new Production(15, T_, Symbol.Epsilon);
            var P6 = new Production(16, F, lb, E, rb);
            var P7 = new Production(17, F, a);

            var grammar = new Grammar(Start, PST, P0, P1, P2, P3, P4, P5, P6, P7);

            //var grammar =new Grammar(Start, PST, P0, P1, P2, P3, P4);


            //LR0Builder b = new LR0Builder(grammar, LR0Builder.BuildMethod.SLR);

            //var table = Builder.Build(grammar, Builder.BuildMethod.LALR);
            //List<Symbol> code = new List<Symbol> { lb, a, Symbol.EOF };


            //Lexer lex = new Lexer(null);
            //Parser parser = new Parser(table, lex, null);

            //try
            //{
            //    parser.DoParse();
            //}
            //catch (AcceptException ex)
            //{
            //    int wut = 0;
            //}
            //catch (NotAcceptException ec)
            //{
            //    int trt = 0;
            //}
            ////string str = b.VisualGraph();
            ////File.WriteAllText(@"C:\Users\silent\Desktop\Machine\lalrEps.gv", str);

            //Console.WriteLine(table.Print());
            ////var Z = new Nonterminal(0, "Z");
            //var S = new Nonterminal(1, "S");
            //var A = new Nonterminal(2, "A");

            //var a = new Terminal(4, "a");
            //var b = new Terminal(5, "b");
            //var c = new Terminal(6, "c");

            //var P0 = new Production(0, Z, S);
            //var P1 = new Production(1, S, S, b);
            //var P2 = new Production(2, S, b, A, a);
            //var P3 = new Production(3, A, a, S, c);
            //var P4 = new Production(5, A, a);
            //var P5 = new Production(6, A, a, S, b);

            //var grammar = new Grammar(Z, P0, P1, P2, P3, P4, P5);
            ////////var grammar = G2();

            ////////var first = SetFactory.CreateFirstSets(grammar);
            ////////int wait = 0;


            ////////var follow = SetFactory.CreateFollowSets(grammar, first);

            //var x = first[new Nonterminal(0, "Z")];
            //int wait2 = 0;
            // var S = new Nonterminal(1, "S");
            // var A = new Nonterminal(2, "A");
            // var B = new Nonterminal(3, "B");

            // var a = new Terminal(4, "a");
            // var b = new Terminal(5, "b");
            // var c = new Terminal(6, "c");
            // var d = new Terminal(7, "d");


            // var P0 = new Production(0, S, b, A, c);
            // var P1 = new Production(1, S, b, B, a);
            // var P2 = new Production(2, A, d);
            // var P3 = new Production(3, B, Symbol.Epsilon);

            // Grammar grammar = new Grammar(S, P0, P1, P2, P3);


            // Console.WriteLine(grammar);

            // LR0Builder l0build = new LR0Builder(grammar);
            // l0build.BuildStatemachine();
            // var tab = l0build.BuildTable(LR0Builder.BuildMethod.LR0);
            // Console.WriteLine(tab.Print());

            //// Console.WriteLine("\n\nParseTable:\n\n");
        }

        private static Grammar Aufgabe2_2()
        {
            var Start = new Nonterminal(0, "Start");
            var S = new Nonterminal(1, "S");
            var X = new Nonterminal(2, "X");
            var Y = new Nonterminal(3, "Y");

            var a = new Terminal(4, "a");
            var b = new Terminal(5, "b");
            var c= new Terminal(6, "c");

            var PST = new Production(0, Start, S);
            var P0 = new Production(1, S, a, X, a, b);
            var P1 = new Production(2, S, Y);
            var P2 = new Production(3, X, b, Y, a);
            var P3 = new Production(4, X, Symbol.Epsilon);
            var P4 = new Production(5, Y, S, c);

            return new Grammar(Start, PST, P0, P1, P2, P3, P4);
        }



        private static Grammar Aufgabe2_1()
        {
            var Start = new Nonterminal(0, "Z");
            var S = new Nonterminal(1, "S");
            var A = new Nonterminal(2, "A");
            var B = new Nonterminal(3, "B");

            var a = new Terminal(4, "a");
            var b = new Terminal(5, "b");

            var PST = new Production(0, Start, S);
            var P0 = new Production(1, S, a, B, a);
            var P1 = new Production(2, B, b, A, b);
            var P2 = new Production(3, B, Symbol.Epsilon);
            var P3 = new Production(4, A, S);

            return new Grammar(Start, PST, P0, P1, P2, P3);
        }

        private static Grammar Aufgabe1_4()
        {
            var Start = new Nonterminal(-1, "Z");
            var S = new Nonterminal(0, "S");
            var A = new Nonterminal(1, "A");
            var B = new Nonterminal(2, "B");

            var a = new Terminal(3, "a");
            var b = new Terminal(4, "b");
            var c = new Terminal(5, "c");
            var d = new Terminal(6, "d");


            var PSt = new Production(-1, Start, S);
            var P0 = new Production(0, S, b, A, c);
            var P1 = new Production(1, S, b, B, a);
            var P2 = new Production(2, A, d);
            var P3 = new Production(3, B, Symbol.Epsilon);


            var grammar = new Grammar(Start, PSt, P0, P1, P2, P3);
            return grammar;
        }


        private static Grammar G0()
        {
            var S = new Nonterminal(0, "S");
            var A = new Nonterminal(1, "A");
            var B = new Nonterminal(2, "B");

            var a = new Terminal(3, "a");
            var b = new Terminal(4, "b");
            

            var P0 = new Production(0, S, a, B);
            var P1 = new Production(1, B, b, A);
            var P2 = new Production(2, B, a);
            var P3 = new Production(3, A, S);
   
            var grammar = new Grammar(S, P0, P1, P2, P3);
            return grammar;
        }

        private static Grammar G1()
        {
            var Z = new Nonterminal(0, "Z");
            var S = new Nonterminal(1, "S");
            var A = new Nonterminal(2, "A");

            var a = new Terminal(4, "a");
            var b = new Terminal(5, "b");
            var c = new Terminal(6, "c");

            var P0 = new Production(0, Z, S);
            var P1 = new Production(1, S, S, b);
            var P2 = new Production(2, S, b, A, a);
            var P3 = new Production(3, A, a, S, c);
            var P4 = new Production(5, A, a);
            var P5 = new Production(6, A, a, S, b);

            var grammar = new Grammar(Z, P0, P1, P2, P3, P4, P5);
            return grammar;
        }

        //http://de.wikipedia.org/wiki/LL%28k%29-Grammatik
        //scheiß auf wiki. dort ist epsilon in den follow mengen
        //siehe: dragon Seite 268. danach ist first und insb. follow korrekt,
        //auch für grammatiken mit epsilon-produktionen :)
        static Grammar G2()
        {
            //var E = new Nonterminal(0, "E");
            //var E_ = new Nonterminal(1, "E'");
            //var T = new Nonterminal(2, "T");
            //var T_ = new Nonterminal(3, "T'");
            //var F = new Nonterminal(4, "F");

            //var a = new Terminal(5, "a");
            //var lb = new Terminal(6, "(");
            //var rb = new Terminal(7, ")");
            //var plus = new Terminal(8, "+");
            //var mul = new Terminal(9, "*");

            //var P0 = new Production(10, E, T, E_);
            //var P1 = new Production(11, E_, plus, T, E_);
            //var P2 = new Production(12, E_, Symbol.Epsilon);
            //var P3 = new Production(13, T, F, T_);
            //var P4 = new Production(14, T_, mul, F, T_);
            //var P5 = new Production(15, T_, Symbol.Epsilon);
            //var P6 = new Production(16, F, lb, E, rb);
            //var P7 = new Production(17, F, a);

            //return new Grammar(E, P0, P1, P2, P3, P4, P5, P6, P7);

            //var Start = new Nonterminal(0, "Z");
            var Start = new Nonterminal(0, "Z");

            var E = new Nonterminal(0, "E");
            var E_ = new Nonterminal(1, "E'");
            var T = new Nonterminal(2, "T");
            var T_ = new Nonterminal(3, "T'");
            var F = new Nonterminal(4, "F");

            var a = new Terminal(5, "a");
            var lb = new Terminal(6, "(");
            var rb = new Terminal(7, ")");
            var plus = new Terminal(8, "+");
            var mul = new Terminal(9, "*");

            var PST = new Production(0, Start, E);

            var P0 = new Production(10, E, T, E_);
            var P1 = new Production(11, E_, plus, T, E_);
            var P2 = new Production(12, E_, Symbol.Epsilon);
            var P3 = new Production(13, T, F, T_);
            var P4 = new Production(14, T_, mul, F, T_);
            var P5 = new Production(15, T_, Symbol.Epsilon);
            var P6 = new Production(16, F, lb, E, rb);
            var P7 = new Production(17, F, a);

            var grammar = new Grammar(Start, PST, P0, P1, P2, P3, P4, P5, P6, P7);
            return grammar;
        }

    }
}
